package com.zlkj.sms.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.Frame;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author lzw
 * @description 视频录像
 * @date 2021/1/22
 */
@Data
@Slf4j
public class VideoRecord extends Thread {

    /**
     * ffmpeg拉取流对象
     */
    private FFmpegFrameGrabber grabber;

    @Autowired
    private VideoPlayWebSocket ws;

    private String rtspUrl = "";
    private String serialId = "0";
    private String fileName = "123456789.mp4";

    private int width = 600;
    private int height = 400;

    private boolean recordState = false;

    public VideoRecord(String rtspUrl, String serialId, int width, int height, String fileName){
        this.rtspUrl = rtspUrl;
        this.serialId = serialId;
        this.width = width;
        this.height = height;
        this.fileName = Tools.stringSplicing(Tools.getOS_ImgUrl(FileType.VIDEO), "/" , fileName , ".mp4");
        this.grabber = pull(rtspUrl, width, height);
    }

    @Override
    public void run() {
        this.recordState = true;
        this.record();
    }

    /**
     * 开始拉取原视频流
     * @param rtspUrl
     * @param width
     * @param height
     * @return
     */
    public FFmpegFrameGrabber pull(String rtspUrl, int width, int height){
        try{
            FFmpegFrameGrabber grabber = FFmpegFrameGrabber.createDefault(rtspUrl);
            grabber.setOption("rtsp_transport", "tcp");
            grabber.setFrameRate(25D);
            grabber.setImageWidth(width);
            grabber.setImageHeight(height);
            grabber.setVideoBitrate(2_000_000);
            grabber.start();

            return grabber;
        }catch (Exception e){
            log.error("pull stream exception:", e.getMessage());
        }
        return null;
    }

    /**
     * 记录视频流到指定文件
     */
    public void record(){
        FFmpegFrameGrabber grabber = this.grabber;
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(this.fileName, grabber.getImageWidth(), grabber.getImageHeight(), grabber.getAudioChannels());
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        recorder.setFormat("mp4");
        recorder.setFrameRate(grabber.getFrameRate());
        recorder.setVideoBitrate(grabber.getVideoBitrate());
        recorder.setAudioBitrate(192000);
        recorder.setAudioOptions(grabber.getAudioOptions());
        recorder.setAudioQuality(0);
        recorder.setSampleRate(44100);
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);

        try {
            recorder.start();
            int loseNum = 0;
            while (this.recordState) {
                try {
                    Frame frame = grabber.grabFrame();

                    if (frame == null) {
                        log.error("video record found lose data, device code:", this.serialId);
                        loseNum++;
                        if(loseNum > 50){
                            break;
                        }else{
                            continue;
                        }
                    }
                    loseNum = 0;
                    recorder.record(frame);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            log.error("video record stop, device code:", this.serialId);

            recorder.stop();
            recorder.release();
            grabber.stop();
            grabber.release();
            recorder.close();
            grabber.close();

            this.grabber = null;
        } catch (Exception e) {
            log.error("video record found exception:", this.serialId);
        }
    }
}
